package com.zzb.framework.query.sqlbuilder;

import com.baomidou.mybatisplus.annotations.TableField;
import com.google.common.collect.Lists;
import com.zzb.framework.common.PageSearchForm;
import com.zzb.framework.query.QueryMethodEnum;
import com.zzb.framework.query.QueryMethodItem;
import com.zzb.framework.utils.DateUtil;
import com.zzb.framework.utils.ReflectionUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;

/**
 * 创建搜索方法的美剧
 * Created by zhangzhenbin on 2016/12/29.
 */
public class QueryMethodBuilder {
    private static final Logger logger = LoggerFactory.getLogger(QueryMethodBuilder.class);

    public static <T extends PageSearchForm> List<QueryMethodItem> build(T searchForm, Class tableClazz) throws IllegalAccessException, NoSuchFieldException {
        List<QueryMethodItem> list = new ArrayList<>();
        Class<? extends PageSearchForm> searchFormClazz = searchForm.getClass();
        Field[] searchFormFields = ReflectionUtils.getAllDeclaredFields(searchFormClazz);
        for (Field searchFormField : searchFormFields) {
            //如果是pageSize，curPageNO，pageProvider字段，则直接忽略
            if (searchFormField.getName().equals("pageSize")
                    || searchFormField.getName().equals("curPageNO")
                    || searchFormField.getName().equals("pageProvider")
                    || searchFormField.getName().equals("orderBy")) continue;
            //如果是有Transient注解，也直接忽略
            if ((searchFormField.getModifiers() & Modifier.TRANSIENT) != 0) continue;

            String searchFormFieldName = searchFormField.getName();
            QueryMethodEnum[] enums = QueryMethodEnum.values();
            for (QueryMethodEnum anEnum : enums) {
                if (searchFormFieldName.startsWith(anEnum.name() + "_")) {
                    QueryMethodItem queryMethodItem = new QueryMethodItem();
                    queryMethodItem.setMethod(anEnum);
                    String fieldName = searchFormFieldName.replace(anEnum.name() + "_", "");
                    if (!anEnum.equals(QueryMethodEnum.in)) {
                        queryMethodItem.setValue(FieldUtils.readDeclaredField(searchForm, searchFormFieldName, true));
                    } else {
                        try {
                            Object o = FieldUtils.readDeclaredField(searchForm, searchFormFieldName, true);
                            if(o instanceof String){
                                String s = (String) o;
                                String[] strings = s.split(",");
                                queryMethodItem.setValues(Lists.newArrayList(strings));
                            } else if(o instanceof Collection){
                                queryMethodItem.setValues((List) o);
                            } else if(o instanceof Object[]){
                                Object[] objects = (Object[]) o;
                                queryMethodItem.setValues(Lists.newArrayList(objects));
                            } else {
                                logger.error("搜索条件["+searchFormFieldName+"]构建失败,in搜索条件的类型必须是String或Collection或Object[]");
                                continue;
                            }
                        } catch (IllegalAccessException e) {
                            logger.error("搜索条件["+searchFormFieldName+"]构建失败",e);
                            continue;
                        }
                    }
                    try {
                        Field declaredField = ReflectionUtils.getAllDeclaredField(tableClazz, fieldName);
                        queryMethodItem.setType(declaredField.getType());
                        TableField columnAnnotation = declaredField.getAnnotation(TableField.class);
                        if(columnAnnotation != null){
                            String columnName = columnAnnotation.value();
                            queryMethodItem.setColumnName(columnName);
                        } else {
                            queryMethodItem.setColumnName(declaredField.getName());
                        }

                    } catch (Exception e) {
                        logger.error("没有在[" + tableClazz.getName() + "]中找到[" + fieldName + "]字段");
                        continue;
                    }

                    list.add(queryMethodItem);
                }
            }

        }
        return list;
    }

    /**
     * 将 methodItemList转换为SQL 和 参数
     *
     * @param methodItemList
     * @param sqlCondition
     * @param params
     */
    public static void methodItemListBuilder(List<QueryMethodItem> methodItemList, StringBuilder sqlCondition, List<Object> params) {
        for (QueryMethodItem item : methodItemList) {
            //包含空值就取消
            if (item.getMethod() == null ||
                    StringUtils.isBlank(item.getColumnName()) ||
                    item.getType() == null ||
                    (item.getValue() == null && !item.getMethod().equals(QueryMethodEnum.in)) ||
                    (CollectionUtils.isEmpty(item.getValues()) && item.getMethod().equals(QueryMethodEnum.in)) ||
                    (item.getValue() instanceof String && StringUtils.isBlank((String) item.getValue()))
                    ) continue;
            if(!item.getMethod().equals(QueryMethodEnum.in)){
                sqlCondition
                        .append("and ")
                        .append("t.")
                        .append(item.getColumnName())
                        .append(" ")
                        .append(item.getMethod().getValue())
                        .append(" ? ");
                Object value = item.getValue();
                if (item.getMethod().equals(QueryMethodEnum.contain)) {
                    value = "%" + value + "%";
                }
                if (item.getType().equals(Date.class) && value instanceof String) {
                    value = DateUtil.stringForceToDate((String) value);
                }
                params.add(value);
            } else {
                sqlCondition
                        .append("and ")
                        .append("t.")
                        .append(item.getColumnName())
                        .append(" in (");
                for (Object o : item.getValues()) {
                    sqlCondition.append(" ? ,");
                    params.add(o);
                }
                sqlCondition.deleteCharAt(sqlCondition.length() - 1);
                sqlCondition.append(" ) ");
            }
        }
    }
}
